<?php
/*
 * program:	均源
 * author:	雨中漫步 & 上善若水 & qhxin
 * email:	qhxin@qhxin.com
 * date:	2014/11/11
 * description:	又是一年双十一，不能剁手，就写点东西吧~~~~~~
 */
/****************************************
XTpl Template Engine for PHP

Developer:  http://www.weentech.com
Version: 2.0
Requirement: PHP 5.0 or Above
****************************************/
defined('IN_SCHOOL') or die();

/*{TranslateTagBegin}*/
class XTpl{
	var $_tpl_vars             = array();
	var $tpl_left_delimiter  =  '{';
	var $tpl_right_delimiter =  '}';
	var $tpl_template_dir    =  'templates/';
	var $tpl_compile_dir     =  'cache/';
	var $tpl_safe_mode = false;
	var $tpl_check = true;
	var $tpl_from_plugin = false;
	
	public function __construct($options) {
		if(isset($options[0]))$this->tpl_template_dir = $options[0];
		if(isset($options[1]))$this->tpl_compile_dir = $options[1];
		if(isset($options[2]))$this->tpl_safe_mode = $options[2];
		if(isset($options[3]))$this->tpl_check = $options[3];
	}

	public function assign($tpl_var, $value = null){
		if (is_array($tpl_var)){
			foreach ($tpl_var as $key => $val) {
				if ($key != '') $this->_tpl_vars[$key] = $val;
			}
		} else {
			if ($tpl_var != '')	$this->_tpl_vars[$tpl_var] = $value;
		}
	}

	public function display($tpl, $return = false){
		$tplTemp = explode('/',  $tpl); //支持下级目录, 如: $tpl->display('dir1/xxxx.tpl');

		if(count($tplTemp) > 1){
			$tplCacheDir = $this->tpl_compile_dir . $tplTemp[0] . '/';
			$tpl_real  = $this->tpl_template_dir . $tplTemp[0] . '/' . $tplTemp[1]; //模板文件路径
			$compiled_file = $tplCacheDir . base64_encode($tplTemp[1]) . ".%%.tpl"; //缓存文件路径
			$this->seatch_plugin_template($tpl_real, $tplTemp[0].'/'.$tplTemp[1]);
		}else{
			$tplCacheDir = $this->tpl_compile_dir;
			$tpl_real  = $this->tpl_template_dir . $tpl;
			$compiled_file = $tplCacheDir . base64_encode($tpl) . ".%%.tpl";
			$this->seatch_plugin_template($tpl_real, $tpl);
		}

		//未编译或模板文件已修改时, 编译生成模板缓存文件
		defined('DEBUG') or define('DEBUG', 0);
		if(DEBUG || (!is_file($compiled_file) || ($this->tpl_check && filemtime($tpl_real)>filemtime($compiled_file)))){
			if(!is_dir($tplCacheDir)){
				mkdir($tplCacheDir, 0777, true);
			}
			$content = file_get_contents($tpl_real);
			misc::in_key_str($tpl_real, CONFIG_PLG_PATH) && core::plugin_payed_relic($content, $tpl_real);
			if(!$this->tpl_from_plugin) {
				$pattern = '/{\/\/hook ([a-zA-Z_]+)\.htm}/';
				$content = preg_replace_callback($pattern,'core::hooks_process_view',$content);
			}
			$compiled_contents = $this->_compile($content);
			file_put_contents($compiled_file, $compiled_contents, LOCK_EX);
		}
		if($return) {
			return file_get_contents($compiled_file);
		}else{
			include($compiled_file);
		}
	}
	
	private function seatch_plugin_template(&$tpl_real,$tpl) {
		if(!file_exists($tpl_real)) {
			//插件template
			foreach(core::$installed_plugin_conf['template'] as $rand=>$arr) {
				if(in_array($tpl,$arr)){
					$id = core::$installed_plugin_conf['baseinfo'][$rand]['id'];
					$tpl_real = CONFIG_PLG_PATH.$id."/$tpl";
					break;
				}
			}
			if(!file_exists($tpl_real)) {
				throw new Exception($tpl_real.' does not exists.');
			}
			$this->tpl_from_plugin = true;
		}
	}

	private function _match($matches){
		$content = $matches[1];
		$subcontent = false;
		//include或require包含文件
		if(preg_match('/^(include|require)\s+["|\']?([\w\.\-\/]+)["|\']?$/msi', $content, $matches)){
			$subcontent = true;
			$content = $this->display($matches[2], $subcontent);
		}else{
			//替换 if,elseif,/if; foreach,/foreach; for,/for
			$pattern = "/^(if|foreach|for)(([\s|\(]+)(.+))/msi";
			$content = preg_replace_callback($pattern,create_function('$m','$t = trim($m[3]);$v = trim($m[2]);if(empty($t)){return "{$m[1]}($v){";}else{return "{$m[1]}$v{";}'),$content);
			$patterns = array("/^(elseif)([\s*|\\(].*)/msi","/^(else)/msUi","/^\/(if|foreach|for)/msi");
			$replacements=array('}\\1(\\2){','}\\1{','}');
			$content = preg_replace($patterns,$replacements,$content);

			//替换变量或输出变量(包括对象成员变量或函数)
			$patterns = array('/\$(\w+)/ms', '/^(\$this->_tpl_vars((\[["|\']\w+["|\']\])+)(->.+)*)$/ms');
			$replacements=array("\$this->_tpl_vars['\\1']", "echo \\1");

			$content = preg_replace($patterns, $replacements, $content);
		}

		$content= $subcontent ? $content : "<?php $content; ?>";
		return $content;
	}

	//编译
	private function _compile($content){
		$left_delimiter_quote = preg_quote($this->tpl_left_delimiter);
		$right_delimiter_quota= preg_quote($this->tpl_right_delimiter);

		//安全模式, 替换php可执行代码
		if($this->tpl_safe_mode){
			$pattern="/\\<\\?.*\\?>/msUi";
			$content = preg_replace($pattern, '<!-- PHP CODE REPLACED ON SAFE MODE -->', $content);
		}

		//替换注释: {*xxx*}
		$pattern="/{$left_delimiter_quote}\*(.*)\*{$right_delimiter_quota}/msU";
		$content = preg_replace($pattern, "<?php /*\\1*/?>", $content);

		//调用_match函数编译
		$pattern="/{$left_delimiter_quote}([\S].*){$right_delimiter_quota}/msU";
		return preg_replace_callback($pattern, array(&$this, '_match'), $content);
	}

	//清空当前模板缓存
	public function clear_compiled_tpl(){
		tpl_remove_cache($this->tpl_compile_dir);
	}
}

/*{TranslateTagEnd}*/

?>